const crypto = require('crypto');
const axios = require('axios');
const config = require('../config/wechat');
const { WECHAT_API } = require('../config/constants');
const ErrorHandler = require('../utils/errorHandler');
const db = require('../models');
const weatherService = require('./weatherService');
const scheduleService = require('./scheduleService');
const { RETRY_POLICY } = require('../config/constants');
class WechatService {
  constructor() {
    this.config = config;
    this.accessToken = null;
    this.tokenExpires = 0;
  }

  // 验证微信服务器
  verifyServer(signature, timestamp, nonce, echostr) {
    const token = config.token;
    const str = [token, timestamp, nonce].sort().join('');
    const sha1 = crypto.createHash('sha1').update(str).digest('hex');
    
    return sha1 === signature ? echostr : false;
  }

  // 通过code获取openid（带重试机制）
  async getOpenidByCode(code) {
    return ErrorHandler.withRetry(async () => {
      const params = {
        appid: this.config.wechat.appId,
        secret: this.config.wechat.appSecret,
        code,
        grant_type: 'authorization_code'
      };
      
      const response = await axios.get(`${WECHAT_API.BASE_URL}/sns/oauth2/access_token`, { 
        params,
        timeout: 5000 
      });
      
      if (response.data.errcode) {
        ErrorHandler.logError('微信API返回错误', {
          api: 'getOpenidByCode',
          response: response.data
        });
        throw new Error(response.data.errmsg);
      }
      
      return response.data.openid;
    }, {
      maxRetries: RETRY_POLICY.DEFAULT_RETRIES,
      delayMs: RETRY_POLICY.DELAY_MS,
      shouldRetry: (err) => RETRY_POLICY.RETRYABLE_ERRORS.some(code => err.code === code)
    });
  }

  // 生成JS-SDK签名
  async getJsapiSignature(url) {
    const token = await this.getAccessToken();
    const params = {
      access_token: token,
      type: 'jsapi'
    };
    
    try {
      // 获取jsapi_ticket
      const ticketResponse = await axios.get(`${this.config.wechat.apiDomain}/cgi-bin/ticket/getticket`, { params });
      
      if (ticketResponse.data.errcode !== 0) {
        throw new Error(ticketResponse.data.errmsg);
      }
      
      const ticket = ticketResponse.data.ticket;
      const nonceStr = Math.random().toString(36).substr(2, 15);
      const timestamp = Math.floor(Date.now() / 1000);
      
      // 生成签名
      const str = `jsapi_ticket=${ticket}&noncestr=${nonceStr}&timestamp=${timestamp}&url=${url}`;
      const signature = crypto.createHash('sha1').update(str).digest('hex');
      
      return {
        appId: this.config.wechat.appId,
        timestamp,
        nonceStr,
        signature
      };
    } catch (err) {
      console.error('生成JS-SDK签名失败:', err);
      throw new Error('生成签名失败');
    }
  }

  // 获取access_token（带重试机制）
  async getAccessToken() {
    const now = Date.now();
    if (this.accessToken && now < this.tokenExpires) {
      return this.accessToken;
    }

    return ErrorHandler.withRetry(async () => {
      const params = {
        grant_type: 'client_credential',
        appid: this.config.wechat.appId,
        secret: this.config.wechat.appSecret
      };
      
      const response = await axios.get(`${WECHAT_API.BASE_URL}${WECHAT_API.ENDPOINTS.TOKEN}`, { 
        params,
        timeout: 5000 
      });
      
      if (response.data.errcode) {
        throw new Error(response.data.errmsg);
      }
      
      this.accessToken = response.data.access_token;
      this.tokenExpires = now + (response.data.expires_in - WECHAT_API.TOKEN_EXPIRE_BUFFER) * 1000;
      
      return this.accessToken;
    }, {
      maxRetries: RETRY_POLICY.DEFAULT_RETRIES,
      delayMs: RETRY_POLICY.DELAY_MS,
      shouldRetry: (err) => RETRY_POLICY.RETRYABLE_ERRORS.some(code => err.code === code)
    });
  }

  // 处理微信消息
  async handleMessage(xmlData) {
    const { ToUserName, FromUserName, MsgType, Content, Event } = xmlData;
    
    // 记录接收到的消息
    logger.info('收到微信消息', {
      msgType: MsgType,
      event: Event,
      contentLength: Content ? Content.length : 0,
      fromUser: FromUserName
    });

    // 事件处理
    if (MsgType === 'event') {
      if (Event === 'subscribe') {
        // 用户关注事件
        await this.handleSubscribe(FromUserName);
        return this.replyText(FromUserName, ToUserName, '感谢关注！请回复城市名称订阅天气推送');
      }
      if (Event === 'unsubscribe') {
        // 用户取消关注事件
        await this.handleUnsubscribe(FromUserName);
        return 'success';
      }
      return 'success';
    }

    // 文本消息处理
    if (MsgType === 'text') {
      // 验证消息长度
      if (Content.length > 500) {
        logger.warn('消息过长', {
          fromUser: FromUserName,
          contentLength: Content.length
        });
        return this.replyText(FromUserName, ToUserName, '消息过长，请控制在500字符以内');
      }

      // 处理城市订阅
      if (/^订阅\s*[\u4e00-\u9fa5]+$/.test(Content)) {
        const city = Content.replace('订阅', '').trim();
        return this.handleCitySubscription(FromUserName, city);
      }
      
      // 处理取消订阅
      if (/^取消订阅\s*[\u4e00-\u9fa5]+$/.test(Content)) {
        const city = Content.replace('取消订阅', '').trim();
        return this.handleUnsubscribeCity(FromUserName, city);
      }
      
      // 默认回复
      return this.replyText(FromUserName, ToUserName, 
        '请发送"订阅+城市名"来订阅天气推送，例如："订阅北京"\n或发送"取消订阅+城市名"取消订阅');
    }

    return 'success';
  }

  // 处理用户取消关注事件
  async handleUnsubscribe(openid) {
    try {
      await db.User.update(
        { status: 0 },
        { where: { openid } }
      );
      logger.info('用户取消关注', { openid });
    } catch (err) {
      logger.error('处理取消关注失败', {
        openid,
        error: err.message
      });
    }
  }

  // 处理城市取消订阅
  async handleUnsubscribeCity(openid, city) {
    try {
      const user = await db.User.findOne({ where: { openid } });
      if (!user) {
        return this.replyText(openid, this.config.wechat.appId, '未找到用户信息');
      }

      const subscription = await db.Subscription.findOne({
        where: {
          userId: user.id,
          cityName: city
        }
      });

      if (!subscription) {
        return this.replyText(openid, this.config.wechat.appId, `您未订阅${city}的天气推送`);
      }

      await subscription.update({ weatherEnabled: false });
      return this.replyText(openid, this.config.wechat.appId, `已取消${city}的天气推送`);
    } catch (err) {
      logger.error('取消城市订阅失败', {
        openid,
        city,
        error: err.message
      });
      return this.replyText(openid, this.config.wechat.appId, '取消订阅失败，请稍后再试');
    }
  }

  // 处理用户关注事件
  async handleSubscribe(openid) {
    // 保存用户信息到数据库
    await db.User.create({
      openid,
      subscribeTime: new Date(),
      status: 1
    });
  }

  // 处理城市订阅
  async handleCitySubscription(openid, city) {
    try {
      // 验证城市有效性
      await weatherService.getWeatherByAMap(city);
      
      // 查找或创建用户
      const [user] = await db.User.findOrCreate({
        where: { openid },
        defaults: {
          openid,
          subscribeTime: new Date(),
          status: 1
        }
      });
      
      // 创建或更新订阅
      const [subscription] = await db.Subscription.findOrCreate({
        where: { userId: user.id, cityName: city },
        defaults: {
          userId: user.id,
          cityCode: city, // 实际项目中应使用城市编码
          cityName: city,
          pushTime: '08:00',
          weatherEnabled: true,
          trafficEnabled: true,
          status: 1
        }
      });
      
      // 更新定时任务
      scheduleService.createSchedule(subscription);
      
      return this.replyText(openid, this.config.wechat.appId, 
        `已成功订阅${city}的天气推送，每天8点将为您推送最新天气信息`);
    } catch (err) {
      console.error('城市订阅失败:', err);
      return this.replyText(openid, this.config.wechat.appId, 
        `订阅失败: ${err.message}`);
    }
  }

  // 回复文本消息
  replyText(fromUser, toUser, content) {
    const timestamp = Math.floor(Date.now() / 1000);
    return `<xml>
      <ToUserName><![CDATA[${fromUser}]]></ToUserName>
      <FromUserName><![CDATA[${toUser}]]></FromUserName>
      <CreateTime>${timestamp}</CreateTime>
      <MsgType><![CDATA[text]]></MsgType>
      <Content><![CDATA[${content}]]></Content>
    </xml>`;
  }

  // 发送模板消息（带重试机制）
  async sendTemplateMessage(openid, templateId, data, url) {
    return ErrorHandler.withRetry(async () => {
      const accessToken = await this.getAccessToken();
      const message = {
        touser: openid,
        template_id: templateId,
        url: url || '',
        data: data
      };

      const response = await axios.post(
        `${WECHAT_API.BASE_URL}${WECHAT_API.ENDPOINTS.MESSAGE_SEND}`,
        message,
        {
          params: { access_token: accessToken },
          timeout: 5000
        }
      );

      if (response.data.errcode !== 0) {
        ErrorHandler.logError('发送模板消息失败', {
          api: 'sendTemplateMessage',
          openid: Encryption.hash(openid), // 记录哈希后的openid
          response: response.data
        });
        throw new Error(response.data.errmsg);
      }
      
      return response.data;
    }, {
      maxRetries: RETRY_POLICY.DEFAULT_RETRIES,
      delayMs: RETRY_POLICY.DELAY_MS,
      shouldRetry: (err) => RETRY_POLICY.RETRYABLE_ERRORS.some(code => err.code === code)
    });
  }
}

module.exports = new WechatService();
